<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="dns-prefetch" href="https://cdn.jsdelivr.net/" />
    <link rel="dns-prefetch" href="https://cdnjs.cloudflare.com/" />
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title></title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/water.css@2.1.1/out/water.min.css" integrity="sha256-QST90Wzz4PEr5KlclQaOCsjc00FTyf86Wrj41oqZB4w=" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css" integrity="sha512-Kc323vGBEqzTmouAECnVceyQqyqdsSiqLQISBL29aUW4U/M7pSPA/gEUZQqv1cwx4OnYxTxve5UMg5GT6L4JJg==" crossorigin="anonymous" referrerpolicy="no-referrer" />
    <style type="text/css">
        body {
            max-width: 85%;
        }

        .inverse {
            -webkit-transform: scaleX(-1);
            -moz-transform: scaleX(-1);
            -o-transform: scaleX(-1);
            transform: scaleX(-1);
            filter: FlipH;
            -ms-filter: "FlipH";
        }

        #list li {
            list-style-type: none;
        }

        #list li {
            a, strong {
                margin-left: 0.4rem;
            }
        }

        .filesize {
            margin-left: 0.25rem;
        }
    </style>
    <script type="text/javascript">
        window.addEventListener('DOMContentLoaded', init);
        let data = {};

        function init() {
            parseCurrentPath();

            const dataElement = document.querySelector('#autoindex-data');
            if (!dataElement) {
                return;
            }

            data = JSON.parse(dataElement.textContent);
            dataElement.remove();
            const list = document.querySelector('#list');

            if (data.length === 0) {
                list.insertAdjacentHTML('beforeend', '<li><i class="fa-solid fa-folder-minus fa-fw"></i> <strong>There are no files to be found in this directory.</strong></li>');
                return;
            }

            data.sort(sortFiles);

            for (const entry of data)
            {
                const { name, type, mtime, size } = entry;
                const isDirectory = type === 'directory';

                const link = document.createElement('a');
                link.textContent = name;
                link.setAttribute('href', name);

                const filesize = document.createElement('span');
                filesize.classList.add('filesize');
                filesize.textContent = `- ${humanFileSize(size)}`;

                const icon = document.createElement('i');
                icon.classList.add('fa-solid', 'fa-fw');
                icon.classList.add(isDirectory ? 'fa-folder-open' : resolveFileIcon(name));

                const listItem = document.createElement('li');
                listItem.insertAdjacentElement('beforeend', icon);
                listItem.insertAdjacentElement('beforeend', link);
                
                if (!isDirectory) {
                    listItem.insertAdjacentElement('beforeend', filesize);
                }

                list.insertAdjacentElement('beforeend', listItem);
            }
        }

        // Parse the path and use for <title> and header
        function parseCurrentPath()
        {
            const url = new URL(window.location.href);
            const path = decodeURIComponent(url.pathname);
            const folderName = path.replace(/((^\/)|(\/$))/g, '').split('/').pop();

            const headerPathElement = document.querySelector('#header-path');
            if (headerPathElement) {
                headerPathElement.textContent = folderName;
            }

            document.title = path;
        }

        // Get matching Font Awesome icon class for the file
        function resolveFileIcon(path) {
            const defaultIcon = 'fa-file';
            if (typeof path !== 'string') {
                return defaultIcon;
            }

            const videoTypes = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'mkv', 'webm', 'mpeg', 'm4v', '3gp', 'av1'];
            const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'tiff', 'svg', 'webp', 'ico', 'heic', 'avif', 'jxl'];
            const documentTypes = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rtf', 'odt', 'ods', 'odp'];
            const archiveTypes = ['7z', 'rar', 'zip'];

            const filename = path.replace(/((^\/)|(\/$))/g, '').split('/').pop();
            const fileExtension = filename.split('.').pop();

            if (!fileExtension) {
                return defaultIcon;
            }

            const type = fileExtension.toLowerCase().trim();
            if (videoTypes.includes(type)) {
                return 'fa-file-video';
            }

            if (imageTypes.includes(type)) {
                return 'fa-file-image';
            }

            if (documentTypes.includes(type)) {
                return 'fa-file-lines';
            }

            if (archiveTypes.includes(type)) {
                return 'fa-file-zipper';
            }

            return defaultIcon;
        }

        // Sort files by directories first, then alphabetically.
        function sortFiles(a, b) {
            if (a.type === b.type) {
                return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
            }

            if (a.type === 'directory') {
                return -1;
            }

            // b.type === 'directory'
            return 1;
        }

        /**
         * Format bytes as human-readable text.
         * Function shameless copied from: https://github.com/EthraZa/NGINdeX.io/blob/main/header.html
         * 
         * @param {Number}  bytes Number of bytes.
         * @param {Boolean} si    True to use metric (SI) units, aka powers of 1000. False to use binary (IEC), aka powers of 1024.
         * @param {Number}  dp    Number of decimal places to display.
         * @return Formatted string.
         */
        function humanFileSize(bytes, si = false, dp = 1) {
            const thresh = si ? 1000 : 1024;

            if (Math.abs(bytes) < thresh) {
                return bytes + ' B';
            }
        
            const units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
            let u = -1;
            const r = 10 ** dp;
        
            do {
                bytes /= thresh;
                ++u;
            } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
            
            return bytes.toFixed(dp) + ' ' + units[u];
        }
    </script>
</head>
<body>
    <h1 id="header-path"></h1>
    <ul id="list">
        <li><a href=".."><i class="fa-solid fa-turn-up inverse fa-fw"></i> Go up one folder</a></li>
        <hr />
    </ul>
    <script id="autoindex-data" type="application/json">
[
{ "name":"Lana Rain_Mona-Megistus-Uses-Her-Body-To-Pay-Rent--Genshin-Impact.mp4", "type":"file", "mtime":"Sat, 24 Aug 2024 17:02:14 GMT", "size":3965825784 },
{ "name":"Lana Rain_Mona-Megistus-Uses-Her-Body-To-Pay-Rent--Genshin-Impact.mp4.jpg", "type":"file", "mtime":"Sat, 24 Aug 2024 17:01:27 GMT", "size":271440 }
]</script>
</body>
</html>
